package org.lex.game.sudoku.view.newgame;

import java.awt.BorderLayout;
import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import org.lex.game.sudoku.model.DefaultSudokuModel;
import org.lex.game.sudoku.model.builder.IntArraySudokuBuilder;
import org.lex.game.sudoku.model.builder.SudokuBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import common.Sudokus;

public class HandInputPane extends JPanel {
	public static void main(String[] args) {
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setContentPane(new HandInputPane());
		frame.setSize(400, 300);
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
	}

	private static final long serialVersionUID = 3200267266783290840L;
	private static final String TO_REPLACE = "\t()[]{};|/\\";

	private JLabel titleLabel;
	private JSplitPane splitPane;
	private JScrollPane inputScrollPane;
	private JTextArea inputTextArea;
	private JScrollPane outputScrollPane;
	private JTextArea outputTextArea;

	private DefaultSudokuModel model = new DefaultSudokuModel();

	private Logger log = LoggerFactory.getLogger(HandInputPane.class);

	/**
	 * Create the panel.
	 */
	public HandInputPane() {
		initialize();
	}

	public SudokuBuilder getBuilder() {
		return this.inputChanged();
	}

	private SudokuBuilder inputChanged() {
		String input = this.getInputTextArea().getText().trim();
		List<String> tokens = this.getTokens(input);
		int tokenSize = tokens.size();
		log.info("tokens count=" + tokenSize);
		int gridSize = model.getGridSize();
		if (tokenSize == (gridSize * gridSize)) {
			int min = Integer.MAX_VALUE;
			int[][] data = new int[gridSize][gridSize];
			for (int row = 0; row < gridSize; row++) {
				for (int col = 0; col < gridSize; col++) {
					String str = tokens.get(row * gridSize + col).trim();
					int num = Sudokus.EMPTY_NUMBER;
					if (false == str.isEmpty()) {
						num = Integer.parseInt(str);
						if (num < min) {
							min = num;
						}
					}
					data[row][col] = num;
				}
			}
			log.info("min=" + min);
			for (int row = 0; row < gridSize; row++) {
				for (int col = 0; col < gridSize; col++) {
					int num = data[row][col];
					if (num <= min) {
						data[row][col] = Sudokus.EMPTY_NUMBER;
					}
				}
			}
			IntArraySudokuBuilder builder = new IntArraySudokuBuilder();
			builder.setArray(data);
			model.newGame(builder);
			if (false == model.checkAll(false).isValid()) {
				this.getOutputTextArea().setForeground(Color.RED);
				this.getOutputTextArea().setText("错误: 行/列/块中有重复数字");
			} else {
				this.getOutputTextArea().setForeground(Color.BLACK);
				this.getOutputTextArea().setText(model.toString());
				return builder;
			}
		} else {
			this.getOutputTextArea().setForeground(Color.RED);
			this.getOutputTextArea().setText("错误: 输入了" + tokenSize + " 个数字，目前只支持9x9=81个数字");
		}
		return null;
	}

	private List<String> getTokens(String text) {
		List<String> lines = new ArrayList<>(10);
		StringTokenizer lineBreaker = new StringTokenizer(text.trim(), "\r\n", false);
		while (lineBreaker.hasMoreTokens()) {
			lines.add(lineBreaker.nextToken().trim());
		}

		StringBuilder buf = new StringBuilder();
		List<String> tokens = new ArrayList<>();
		for (String line : lines) {
			if (false == line.isEmpty()) {
				buf.setLength(0);
				buf.append(line);
				for (int i = 0, n = buf.length(); i < n; i++) {
					char ch = buf.charAt(i);
					if (-1 != TO_REPLACE.indexOf(ch)) {
						buf.setCharAt(i, ' ');
					}
				}
				line = buf.toString().trim();

				StringTokenizer tokenBreaker = new StringTokenizer(line, ",", false);
				while (tokenBreaker.hasMoreTokens()) {
					tokens.add(tokenBreaker.nextToken());
				}
			}
		}
		return tokens;
	}

	private void initialize() {
		setLayout(new BorderLayout(0, 0));
		add(getTitleLabel(), BorderLayout.NORTH);
		add(getSplitPane(), BorderLayout.CENTER);
	}

	private JLabel getTitleLabel() {
		if (titleLabel == null) {
			titleLabel = new JLabel("Title");
		}
		return titleLabel;
	}

	private JSplitPane getSplitPane() {
		if (splitPane == null) {
			splitPane = new JSplitPane();
			splitPane.setDividerSize(6);
			splitPane.setResizeWeight(0.7);
			splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
			splitPane.setLeftComponent(getInputScrollPane());
			splitPane.setRightComponent(getOutputScrollPane());
		}
		return splitPane;
	}

	private JScrollPane getInputScrollPane() {
		if (inputScrollPane == null) {
			inputScrollPane = new JScrollPane();
			inputScrollPane.setViewportView(getInputTextArea());
		}
		return inputScrollPane;
	}

	private JTextArea getInputTextArea() {
		if (inputTextArea == null) {
			inputTextArea = new JTextArea();
			inputTextArea.getDocument().addDocumentListener(new DocumentListener() {
				@Override
				public void insertUpdate(DocumentEvent e) {
					inputChanged();
				}

				@Override
				public void removeUpdate(DocumentEvent e) {
					inputChanged();
				}

				@Override
				public void changedUpdate(DocumentEvent e) {
					inputChanged();
				}
			});
		}
		return inputTextArea;
	}

	private JScrollPane getOutputScrollPane() {
		if (outputScrollPane == null) {
			outputScrollPane = new JScrollPane();
			outputScrollPane.setViewportView(getOutputTextArea());
		}
		return outputScrollPane;
	}

	private JTextArea getOutputTextArea() {
		if (outputTextArea == null) {
			outputTextArea = new JTextArea();
			outputTextArea.setEditable(false);
		}
		return outputTextArea;
	}
}
